package com.easyim.imserver.handler.message;

import com.easyim.common.message.Immessage;
import io.netty.channel.Channel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;

import static com.easyim.imserver.constant.CacheKey.*;
import static com.easyim.imserver.utils.RedisKeyUtils.buildSessionMsgKey;
import static com.easyim.imserver.utils.RedisKeyUtils.buildUserReadMsgKey;

@Component
public class AckMsgHandler implements Handler{

    @Autowired
    @Qualifier("msgRedisTemplate")
    private RedisTemplate redisTemplate;

    @Override public String dealType() {
        return ACK_MSG_HANDLER_KEY;
    }

    //todo 收到ack 判断ack是否是最新的 如果是最新的 那么将已读的游标记录为最新 不是最新的 忽略 防止出现先投递的 后ack的极端情况 这个可以作为后期的优化
    //也是redis的一个key 我们的ack是针对端上已接收的 不是说用户读没读 用户读没读这个消息 是端上已经拉取的 没有读的 + 服务器端没有拉取的
    //usr:ack:{device} -> ack最后一次消息的id 下次拉取的时候 就只拉取 zset中 比这个消息分数小的了 获取消息的时间戳 判断时间戳大于这个时间的 才是未读的
    //获取未读消息的接口调用时机！在建立连接 并且成功鉴权后。做一次漫游的拉取
    @Override
    public void handlerMsg(Channel channel, Immessage.ImMessage imMessage) {
        String username = channel.attr(USERNAME).get();
        String device = channel.attr(DEVICE).get();
        //客户端发来ack 那么说明消息到了
        Immessage.AckMessage ackMessage = imMessage.getAckMessage();
        long serverMsgId = ackMessage.getServerMsgId();
        //更新用户已经拉取的消息的游标. 到时候在写个拉消息的
        //读一个删除一个呗 clickhouse存储的数据 可以理解为存档数据。redis存储未读数据
        //获取消息分数。然后在key里面 设置一下
        //user:ack:{username}:{device} -> 最新一条ack的分数
        String sessionId = ackMessage.getSessionId();
        //拿到sessionId 获取session中消息的分数。 然后也就是最新一条客户端已经拉取到的
        //获取消息的发送的时间戳
        String sessionKey = buildSessionMsgKey(sessionId);
        Double score = redisTemplate.opsForZSet().score(sessionKey, serverMsgId);
        if(score != null){
            //记录一下 当前端最新的读取的消息下发时间 这里如果直接存double类型 会出现一个科学记数法的字符串 不可以的 所以还是转成数字
            BigDecimal scoreBigDecimal = BigDecimal.valueOf(score);
            long longScore = scoreBigDecimal.longValueExact();
            redisTemplate.opsForValue().set(buildUserReadMsgKey(username, device), longScore);
        }
        //如果拉取漫游变慢了 那么我们做一个处理 将所有端 以读的最小的分数拿出来 然后删除掉会话中 比这个分数还小的所有消息
    }
}
